using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace iislogreader.Data
{
    /// <summary>
    /// Log Header (W3C Extended)
    /// </summary>
    /// <remarks>
    /// see <a href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/676400bc-8969-4aa7-851a-9319490a9bbb.mspx?mfr=true">W3C Extended Log File Format (IIS 6.0).</a><br/>
    /// </remarks>
    public class W3CHeader
    {
        private String _row;

        /// <summary>
        /// Header Row
        /// </summary>
        public String Row
        {
            get { return _row; }
        }

        private String[] _Fields;

        /// <summary>
        /// Gets values an array of field headers.
        /// </summary>
        public String[] Fields
        {
            get { return _Fields; }
        }
        private Hashtable _FieldTable;

        /// <summary>
        /// W3C Header
        /// </summary>
        /// <code>
        /// #Software: Microsoft Internet Information Services 7.5
        /// #Version: 1.0
        /// #Date: 2012-04-30 04:00:17
        /// #Fields: date time s-sitename s-computername s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs-version cs(User-Agent) cs(Cookie) cs(Referer) cs-host sc-status sc-substatus sc-win32-status sc-bytes cs-bytes time-taken
        /// </code>
        /// <param name="row">Header String(single line)</param>
        /// <exception cref="ArgumentException"><c>row</c> is not header.</exception>
        public W3CHeader(String row)
        {
            if(IsHeader(row)){
                _row = row;
                if (isFieldsHeader())
                {
                    _Fields = HeaderValue().Split(' ');
                    _FieldTable = new Hashtable();
                    for (int i = 0; i < _Fields.Length; i++)
                    {
                        String key = _Fields[i];
                        _FieldTable.Add(key, i);
                    }
                }
            } else {
                Exception ex = new ArgumentException("The row string is not header.");
                throw ex;
            }
        }

        /// <summary>
        /// Gets a value that indicates whether the row is header.
        /// </summary>
        /// <param name="row">IIS Log Header</param>
        /// <returns>return true if the <c>row</c> begins with '#'.</returns>
        public static Boolean IsHeader(String row)
        {
            Boolean result = false;
            if (null == row) 
            {
                result = false;
            }
            else if (row.IndexOf('#') == 0)
            {
                result = true;
            }
            else
            {
                result = false;
            }

            return result;
        }

        /// <summary>
        /// Gets a header name from header row.
        /// </summary>
        /// <remarks>
        /// Ex. returns "Date" if the row like below.
        /// <code>
        /// #Date: 2012-04-30 04:00:17
        /// </code>
        /// </remarks>
        /// <returns>returns header name or null.</returns>
        public String HeaderName()
        {
            String result = null;
            int terminater = _row.IndexOf(':');
            if(terminater > 2){
                result = _row.Substring(1, terminater - 1);
            }
            return result;
        }

        /// <summary>
        /// Gets a header value from header row.
        /// </summary>
        /// <remarks>
        /// Ex. returns "2012-04-30 04:00:17" if the row like below.
        /// <code>
        /// #Date: 2012-04-30 04:00:17
        /// </code>
        /// </remarks>
        /// <returns>returns header value or null.</returns>
        public String HeaderValue()
        {
            String result = null;
            int terminater = _row.IndexOf(':');
            if (terminater > 2 && _row.Length > 3 )
            {
                result = _row.Substring(terminater + 1).Trim();
            }
            return result;
        }

        /// <summary>
        /// Gets a value that indicates whether the row is "Date" header.
        /// </summary>
        /// <returns>return true if the row is "Date" header.</returns>
        public Boolean isDateHeader()
        {
            Boolean result = "Date" == HeaderName();
            return result;
        }

        /// <summary>
        /// Gets a value that indicates whether the row is "Field" header.
        /// </summary>
        /// <returns>return true if the row is "Field" header.</returns>
        public Boolean isFieldsHeader()
        {
            Boolean result = "Fields" == HeaderName();
            return result;
        }

        /// <summary>
        /// Gets a value that indicates whether the row is "Software" header.
        /// </summary>
        /// <returns>return true if the row is "Software" header.</returns>
        public Boolean isSoftwareHeader()
        {
            Boolean result = "Software" == HeaderName();
            return result;
        }

        /// <summary>
        /// Gets a value that indicates whether the row is "Version" header.
        /// </summary>
        /// <returns>return true if the row is "Version" header.</returns>
        public Boolean isVersionHeader()
        {
            Boolean result = "Version" == HeaderName();
            return result;
        }

        /// <summary>
        /// Gets a value of field index.
        /// </summary>
        /// <remarks>
        /// Ex. <c>"#Fields: date time s-sitename"</c><br/>
        /// <c>IndexOfField("date")</c> return 0.<br/>
        /// <c>IndexOfField("s-sitename")</c> return 2.<br/>
        /// <c>IndexOfField("unknown-field")</c> return -1.<br/>
        /// </remarks>
        /// <param name="field">a field name</param>
        /// <returns>return a value of field index or -1.</returns>
        public int IndexOfField(String field)
        {
            int result = -1;
            if (ContainsField(field))
            {
                result = (int)_FieldTable[field];
            }
            return result;
        }

        /// <summary>
        /// Gets a value that indicates whether the field exists.
        /// </summary>
        /// <param name="field">a field name</param>
        /// <returns>return true if the field exists.</returns>
        public Boolean ContainsField(String field)
        {
            Boolean result = _FieldTable.ContainsKey(field);
            return result;
        }
    }
}
